package tests; 

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;

import org.junit.Assert;
import org.junit.Test;
import smashed.CycleWorkSpace;
import smashed.Edge;
import smashed.FinishTimeWorkSpace;
import smashed.GlobalVarsWrapper;
import smashed.Graph;
import smashed.NetworkGenerator;
import smashed.NumberWorkSpace;
import smashed.RegionWorkSpace;
import smashed.TreeGenerator;
import smashed.Vertex;
import smashed.WorkSpaceTranspose;

public class Tests {
	
	@Test
	public void RegionWorkSpacePostVisitActionTest(){
		RegionWorkSpace rws = new RegionWorkSpace();
		Vertex v = new Vertex();
		rws.postVisitAction(v);
		Assert.assertEquals(0, v.componentNumber);
		rws.nextRegionAction(v);
		rws.postVisitAction(v);
		Assert.assertEquals(1, v.componentNumber);
	}
	
	@Test
	public void RegionWorkSpaceInit_vertexTest(){
		Vertex v = new Vertex();
		RegionWorkSpace rws = new RegionWorkSpace();
		
		rws.init_vertex(v);
		Assert.assertEquals(-1, v.componentNumber);
	}
	
	@Test
	public void cycleCheckTest(){
		Graph g = new Graph();
		boolean result = g.CycleCheck();
		Assert.assertFalse(result);
	}
	
	@Test
	public void NumberWorkSpacePreVisitActionTest(){
		NumberWorkSpace nws = new NumberWorkSpace();
		Vertex v = new Vertex();
		
		v.visited = true;
		nws.preVisitAction(v);
		Assert.assertEquals(0, v.VertexNumber);
		
		v.visited = false;
		nws.preVisitAction(v);
		Assert.assertEquals(0, v.VertexNumber);
	}
	
	@Test
	public void strongComponentsTest(){
		Graph g = new Graph();
		
		Vertex v1 = new Vertex();
		Vertex v2 = new Vertex();
		Vertex v3 = new Vertex();
		
		List<Vertex> list = new ArrayList();
		
		v1.finishTime = 1;
		v2.finishTime = 2;
		v3.finishTime = 3;
		
		list.add(v1);
		list.add(v2);
		list.add(v3);
		
		g.vertices.add(v3);
		g.vertices.add(v2);
		g.vertices.add(v1);
		
				
		g.StrongComponents();
		
		for(int i = 0; i < list.size(); i++){
			Assert.assertSame(list.get(i), g.vertices.get(i));
		}
		
	}
	
	@Test
	public void EdgeTest(){
		final Vertex START = new Vertex();
		final Vertex END = new Vertex();
		final int WEIGHT = 10;
		
		Edge edge = new Edge(START, END, WEIGHT);
		Assert.assertSame(START, edge.start);
		Assert.assertSame(END, edge.end);
		Assert.assertEquals(WEIGHT, edge.weight);
	}
	
	@Test
	public void postVisitActionTest(){
		Vertex v = new Vertex();
		CycleWorkSpace cws = new CycleWorkSpace();
		
		cws.postVisitAction(v);
		Assert.assertEquals(CycleWorkSpace.BLACK, v.VertexColor);
		Assert.assertEquals(-1, cws.counter);
	}
	
	@Test
	public void computeTransposeTest(){
		Graph graph = new Graph();
		final int VERTEX = 10;
		for(int i = 0; i < VERTEX; i++){
			graph.addVertex(new Vertex());
		}
		Graph newGraph = graph.ComputeTranspose(graph);
		Assert.assertEquals(VERTEX, newGraph.vertices.size());
	}
	
	@Test
	public void addAnEdge(){
		final int WEIGHT = 10;
		Graph g = new Graph();
		Vertex start = new Vertex(), end = new Vertex();
		g.addAnEdge(start, end, WEIGHT);
		Assert.assertFalse(start.weightsList.isEmpty());
		if(!start.weightsList.isEmpty()){
			Assert.assertEquals(WEIGHT, start.weightsList.getFirst());
		}
	}
	
	@Test
	public void dftNodeSearchTest(){
		Vertex v = new Vertex();
		v.dftNodeSearch(new WorkSpaceTranspose());
		Assert.assertTrue(v.visited);
	}
	
	@Test
	public void assignNameTest(){
		String NEW_NAME = "new name";
		Vertex v = new Vertex();
		v.assignName(NEW_NAME);
		Assert.assertEquals(NEW_NAME, v.name);
	}
	
	@Test
	public void checkNeighborActionTest(){
		CycleWorkSpace cws = new CycleWorkSpace();
		Vertex src = new Vertex(), target = new Vertex();
		//Test with both colors setted to GRAY
		src.VertexColor = CycleWorkSpace.GRAY;
		target.VertexColor = CycleWorkSpace.GRAY;
		cws.checkNeighborAction(src, target);
		Assert.assertTrue(cws.AnyCycles);
		//Test with just target color setted to GRAY
		cws = new CycleWorkSpace();
		src.VertexColor = CycleWorkSpace.BLACK;
		cws.checkNeighborAction(src, target);
		Assert.assertFalse(cws.AnyCycles);
		//Test with just source color setted to GRAY
		cws = new CycleWorkSpace();
		src.VertexColor = CycleWorkSpace.GRAY;
		target.VertexColor = CycleWorkSpace.WHITE;
		cws.checkNeighborAction(src, target);
		Assert.assertFalse(cws.AnyCycles);
		//Test with any color setted to GRAY
		cws = new CycleWorkSpace();
		src.VertexColor = CycleWorkSpace.BLACK;
		cws.checkNeighborAction(src, target);
		Assert.assertFalse(cws.AnyCycles);
	}
	
	@Test
	public void bftNodeSearchTest(){
		final int SIZE = 10;
		Vertex v = new Vertex(), aux;
		v.visited = false;
		for(int i = 0; i < SIZE; i++){
			aux = new Vertex();
			aux.visited = false;
			v.addAdjacent(aux);
		}
		v.bftNodeSearch(new WorkSpaceTranspose());
		Assert.assertEquals(0, GlobalVarsWrapper.Queue.size());		
	}
	
	@Test
	public void getNetworkTest(){
		Object[] expected = {"0 1\n1 11\n0 2\n2 11\n" +
				"0 3\n3 11\n0 4\n4 11\n0 5\n5 11\n0 6\n" +
				"6 11\n0 7\n7 11\n0 8\n8 11\n0 9\n9 11\n" +
				"0 10\n10 11\n", 11, 12, 20};
		Object[] network = NetworkGenerator.getNetwork(0, 10);
		Assert.assertArrayEquals(expected, network);
	}
	
	@Test
	public void finishTimeWorkSpaceTest(){
		Vertex v = new Vertex();
		FinishTimeWorkSpace ftws = new FinishTimeWorkSpace();
		ftws.postVisitAction(v);
		Assert.assertEquals(1, v.finishTime);
		ftws.postVisitAction(v);
		Assert.assertEquals(2, v.finishTime);
	}
	
	@Test
	public void workSpaceTransposeTest(){
		//Testa com o visited = false
		Vertex v = new Vertex();
		v.visited = false;
		WorkSpaceTranspose wst = new WorkSpaceTranspose();
		wst.nextRegionAction(v);
		wst.preVisitAction(v);
		Assert.assertEquals(1, v.strongComponentNumber);
		//Testa com o visited = true
		v = new Vertex();
		v.visited = true;
		wst = new WorkSpaceTranspose();
		wst.nextRegionAction(v);
		wst.preVisitAction(v);
		Assert.assertEquals(0, v.strongComponentNumber);
	}
	
	@Test
	public void init_vertexTest(){
		Vertex v = new Vertex();
		CycleWorkSpace cws = new CycleWorkSpace();
		cws.init_vertex(v);
		// Testa o init_vertex
		Assert.assertEquals(Integer.MAX_VALUE, v.VertexCycle);
		Assert.assertEquals(CycleWorkSpace.WHITE, v.VertexColor);
	}
	
	@Test
	public void cycleWorkSpaceTest() {
		Vertex v = new Vertex();
		CycleWorkSpace cws = new CycleWorkSpace();
		// Testa o construtor de CycleWorkSpace
		Assert.assertFalse(cws.AnyCycles);
		Assert.assertEquals(0, cws.counter);

		v = new Vertex();
		cws = new CycleWorkSpace();
		v.visited = true;
		cws.preVisitAction(v);
		// Testa o preVisitAction com v.visited = true
		Assert.assertEquals(0, v.VertexCycle);
		Assert.assertEquals(CycleWorkSpace.WHITE, v.VertexColor);
		Assert.assertEquals(0, cws.counter);

		v = new Vertex();
		cws = new CycleWorkSpace();
		v.visited = false;
		cws.preVisitAction(v);
		// Testa o preVisitAction com v.visited = false
		Assert.assertEquals(0, v.VertexCycle);
		Assert.assertEquals(CycleWorkSpace.GRAY, v.VertexColor);
		Assert.assertEquals(1, cws.counter);
	}

	@Test
	public void processNodeTest() {

		TreeGenerator.processNode(10, TreeGenerator.MAX_DEPTH);
		Assert.assertEquals(0, TreeGenerator.edgeCount);
		Assert.assertEquals(0, TreeGenerator.nodeCount);

		TreeGenerator.processNode(10, TreeGenerator.MAX_DEPTH - 1);
		Assert.assertEquals(4, TreeGenerator.edgeCount);
		Assert.assertEquals(4, TreeGenerator.nodeCount);
	}

	@Test
	public void findVertexTest() {
		final String NAME = "Name";
		Graph graph = new Graph();
		graph.vertices = new LinkedList();
		Vertex resultVertex, vertex;
		// Find null
		resultVertex = graph.findsVertex(null);
		Assert.assertNull(resultVertex);

		for (int i = 0; i < 10; i++) {
			vertex = new Vertex();
			vertex.name = NAME + i;
			graph.vertices.add(vertex);
		}

		// Find an existent element
		resultVertex = graph.findsVertex(NAME + "5");
		Assert.assertNotNull(resultVertex);
		// Find an non existent element
		resultVertex = graph.findsVertex("Some name");
		Assert.assertNull(resultVertex);
	}
}